# -*- coding: utf-8 -*-
# @Time: 2021/8/21 23:33
# @Author: yuan hao
# @Remark: 视频管理server层
import logging
import os
import time
import socket
from superbsapi import EncryptString
from typing import List

from db.common.VideoManage.VideoQuality.inspection_plan import InspectionPlanDB
from db.common.VideoManage.VideoQuality.inspection_record import InspectionRecordDB
from db.common.VideoManage.VideoQuality.inspection_task import InspectionTaskDB
from db.common.VideoManage.VideoQuality.video import VideoDB
from db.common.VideoManage.VideoQuality.video_group import VideoGroupDB
from model.common.VideoManage.VideoQuality.video import VideoModel, VideoUpdateModel, VideoPreviewSelectModel, VideoDeleteModel
from mxsoftpy import Server
from server.common.VideoManage.VideoQuality.video_analyze import VideoAnalyze
from server.common.VideoManage.VideoQuality.video_type import VideoUrl
from utils.conf.mxconfig import MxConfig
from utils.parser.fields import check_time_stamp
from utils.public.data_process import pwd_web2db
from utils.public.params_method import get_pagination_params, pagination, update_select_params


class VideoServer(Server):
    __model__ = VideoModel
    __db__ = VideoDB

    def test(self, **video_model) -> bool:
        """
        测试视频是否可用
        :param video_model:
        :return:
        """

        # 判断是否是编辑时修改了密码
        if video_model['password'] == MxConfig.UNIVERSAL_PWD and video_model.get('video_code'):
            video_model['password'] = self.db.retrieve(video_model['video_code'])['password']
        else:
            video_model['password'] = pwd_web2db(video_model['password'], video_model['pwd_verify'])

        url = VideoUrl().url('HIKVISION', info=VideoUpdateModel(**video_model).dict())

        # 测试推流服务器的ip和端口是否正常
        socket.setdefaulttimeout(3)
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        res = sock.connect_ex((video_model['server_ip'], MxConfig.SERVER_PORT))

        return True if VideoAnalyze().fetch_url(url) and res == 0 else False

    def create(self, **video_model) -> str:
        """
        新增视频
        :param video_model: 视频模型，字段详情见VideoModel类
        """
        video_model['password'] = pwd_web2db(video_model['password'], video_model['pwd_verify'])  # 转换密码加密

        return self.db.create(**self.model(**video_model).dict())

    def excel_import(self, video_list: List[dict]):
        """
        从excel导入视频
        :param video_list: 视频模型，字段详情见VideoModel类
        """
        err_num = 0
        for video in video_list:
            try:
                group_code = VideoGroupDB().find_code(str(video['group_name']))
                print(group_code)
                print("!!!!!!!!")
                video['password'] = EncryptString(video['password'])[1]
                print(video)
                print(1111111111)
                self.db.excel_create(**self.model(group_code=group_code, **video).dict())
            except Exception as e:
                logging.error(str(e))
                err_num += 1
                continue
        return len(video_list) - err_num, err_num

    def delete(self, **params) -> list:
        """
        删除视频，支持单个code或者批量删除
        :param video_code: 要删除的视频code
        :param delete_type: 要删除的视频关联任务状态 1：关联 2：不关联
        """

        video_delete_model = VideoDeleteModel(**params).dict()
        video_code = video_delete_model['video_code']
        delete_type = video_delete_model['delete_type']
        if delete_type == 1:
            delete_plan_list = video_delete_model['plans']
            delete_task_list = video_delete_model['tasks']
            self.db.relevance_delete(video_code,delete_plan_list,delete_task_list)

        return self.db.delete([video_code])

    @staticmethod
    def delete_check(video_code: str) -> list:
        """
        删除视频校验，支持单个code或者批量校验
        :param video_code: 要删除的视频code
        """
        res_list = []
        delete_task_list = []
        delete_plan_list = []
        video_code_list = video_code.split(';')
        for video_code in video_code_list:
            check_dict = dict()
            check_dict['video_code'] = video_code

            # 模糊查询是否关联（有误差）
            task_dict = InspectionTaskDB().simple_list(videos__like=f'*{video_code}*')
            plan_dict = InspectionPlanDB().simple_list(videos__like=f'*{video_code}*')

            # 代码层确认是否关联
            for plan_code, plan_value in plan_dict.items():
                plan_video_list = plan_value['videos'].split(';')
                if video_code in plan_video_list:
                    delete_plan_list.append(plan_code)

            for task_code, task_value in task_dict.items():
                task_video_list = task_value['videos'].split(';')
                if video_code in task_video_list:
                    delete_task_list.append(task_code)

            if delete_plan_list or delete_task_list:
                check_dict['delete_type'] = 1
                check_dict['plans'] = list(set(delete_plan_list))
                check_dict['tasks'] = list(set(delete_task_list))

            else:
                check_dict['delete_type'] = 0
            res_list.append(check_dict)
        return res_list

    def retrieve(self, video_code: str) -> dict:
        """
        获取视频详情
        :param video_code: 视频code
        """

        res_dict = self.db.retrieve(video_code)
        res_dict['password'] = MxConfig.UNIVERSAL_PWD  # 返回给前端通用密码

        return res_dict

    def update(self, **video_update_model) -> str:
        """
        更新视频
        :param video_update_model: 视频更新模型，详情见VideoUpdateModel类
        """
        # 根据前端返回的是否是通用密码来判断是否需要更新密码
        if video_update_model['password'] == MxConfig.UNIVERSAL_PWD:
            items = VideoUpdateModel(**video_update_model).dict(exclude={'password': ...})  # 排除密码字段
        else:
            video_update_model['password'] = pwd_web2db(video_update_model['password'],
                                                        video_update_model['pwd_verify'])
            items = VideoUpdateModel(**video_update_model).dict()
        return self.db.update(video_update_model['video_code'], **items)

    def move(self, video_code: str, group_code: str) -> List[str]:
        """
        移动视频
        :param video_code: 视频code
        :param group_code: 要移动到的新分组code
        """
        video_list = video_code.split(';')
        return self.db.move(video_list, group_code)

    def select(self, name: str, group_code: str, **paging) -> dict:
        """
        根据名称模糊查询视频
        :param name: 查询关键词
        :param group_code: 所属分组code
        :param paging: 分页参数
        """

        query = get_pagination_params(paging)  # 获取分页参数
        query.update({'state': 1, 'group_code': group_code, 'name__like': '*%s*' % name})
        query = update_select_params(query)
        total, data = self.db.select(**query)

        return pagination(data, query, total)

    def __select_image(self, select_data: VideoPreviewSelectModel) -> dict:
        """
        查询视频图片
        """
        res = InspectionRecordDB().select(videos=[select_data.video_code],
                                          tasks=[select_data.task_code] if select_data.task_code else [],
                                          count=0 if select_data.task_code else 1)

        return {'image': ''.join(['tmp', os.sep, '%s_%s_%s.bmp' % (
             select_data.video_code, res[0]['task_code'], str(res[0]['test_time']))]),
                'find_time': check_time_stamp(res[0]['test_time'])} \
            if res else {'image': '', 'find_time': check_time_stamp(int(time.time()))}

    def preview(self, **select_query) -> dict:
        """
        展示视频图像
        """

        select_data = VideoPreviewSelectModel(**select_query)

        # 根据pre_code来确定返回url还是图片
        video_info = VideoUrl().video_info(select_data.video_code)
        select_dict = {
            '1': {'url': VideoUrl().url('HIKVISION', select_data.video_code),
                  'find_time': check_time_stamp(int(time.time())),
                  'server_ip': video_info.get('server_ip')},
            '0': self.__select_image(select_data)
        }

        return select_dict[select_data.pre_code]
